﻿using HtmlAgilityPack;
using MusicExplorer.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Fizzler.Systems.HtmlAgilityPack;
using MusicExplorer.Repository.Internals;
using System.Net;
using Newtonsoft.Json.Linq;
using System.Globalization;

namespace MusicExplorer.Repository
{
    [Id("85071EF2-C1E7-4953-9A99-98DC3356F840")]
    public sealed class ITunesRepository : RepositoryBase
    {
        private const string m_url_top_100_all = @"https://itunes.apple.com/rss/topsongs/limit=300/json";

        public ITunesRepository(Model.Repository repository)
            : base(repository)
        {
            m_urlAllEntities[EntityType.Genre] =
                @"https://itunes.apple.com/us/genre/music/id34";
            m_urlTracks[new QueryDefinition(QueryType.TopTracks, EntityType.Genre)] =
                @"https://itunes.apple.com/rss/topsongs/limit=300/genre={0}/json";

            m_urlSearchEntities[EntityType.Artist] =
                @"https://itunes.apple.com/search?term={0}&entity=musicArtist&limit=200";
            m_urlTracks[new QueryDefinition(QueryType.AllTracks, EntityType.Artist)] =
                @"https://itunes.apple.com/lookup?id={0}&entity=song&sort=recent&limit=200";
            m_urlTracks[new QueryDefinition(QueryType.TopTracks, EntityType.Artist)] =
                @"https://itunes.apple.com/lookup?id={0}&entity=song&sort=popular&limit=200";
        }

        public override int StartingPage { get { return 1; } }

        public override bool IsMusicStore { get { return true; } }

        protected override string GetTracksUrl(QueryType queryType, Entity entity, int page)
        {
            if(page == StartingPage)
            {
                if (entity.Type == EntityType.Genre && entity.Id == "all")
                {
                    return m_url_top_100_all;
                }
                else
                {
                    return base.GetTracksUrl(queryType, entity, page);
                }
            }
            else
            {
                return string.Empty;
            }
        }

        protected override string GetSearchEntitiesUrl(EntityType type, string terms, int page)
        {
            if (page == StartingPage)
            {
                return base.GetSearchEntitiesUrl(type, terms, page);
            }
            else
            {
                return string.Empty;
            }
        }

        private List<Model.Track> DecodeTracksFromGenre(string source)
        {
            var tracks = new List<Track>();

            var json_tracks = (JArray)JObject.Parse(source)["feed"]["entry"];
            foreach (var jsonTrack in json_tracks)
            {
                var name = (string)jsonTrack["im:name"]["label"];
                var bigArtwork = (string)jsonTrack["im:image"][2]["label"];
                var releaseDate = (DateTime)jsonTrack["im:releaseDate"]["label"];
                var mp3 = (string)jsonTrack["link"][1]["attributes"]["href"];
                var url = (string)jsonTrack["link"][0]["attributes"]["href"];
                var id = (string)jsonTrack["id"]["attributes"]["im:id"];
                var track = new Track(id, m_repository, TrackType.Classic)
                {
                    Artwork = bigArtwork,
                    Mp3 = mp3,
                    Name = name,
                    PublishDate = releaseDate,
                    Url = url
                };

                var artistName = (string)jsonTrack["im:artist"]["label"];
                var artistId = ((string)jsonTrack["im:artist"]["attributes"]["href"]).Split('/').Last().Remove(0, 2).Replace("?uo=2", "");
                var artist = new Artist(artistId, artistName, m_repository);
                track.Artists[ArtistRole.Composer] = new List<Artist>();
                track.Artists[ArtistRole.Composer].Add(artist);

                tracks.Add(track);
            }

            return tracks;
        }

        private List<Model.Track> DecodeTracksFromArtist(string source)
        {
            var tracks = new List<Track>();

            var json_tracks = (JArray)JObject.Parse(source)["results"];
            foreach (var jsonTrack in json_tracks.Where(t => (string)t["wrapperType"] == "track"))
            {
                var name = (string)jsonTrack["trackName"];
                var bigArtwork = (string)jsonTrack["artworkUrl100"];
                var releaseDate = (DateTime)jsonTrack["releaseDate"];
                var mp3 = (string)jsonTrack["previewUrl"];
                var id = (string)jsonTrack["trackId"];
                var url = (string)jsonTrack["trackViewUrl"];
                var track = new Track(id, m_repository, TrackType.Classic)
                {
                    Artwork = bigArtwork,
                    Mp3 = mp3,
                    Name = name,
                    PublishDate = releaseDate,
                    Url = url
                };

                var artistName = (string)jsonTrack["artistName"];
                var artistId = (string)jsonTrack["artistId"];
                var artist = new Artist(artistId, artistName, m_repository);
                track.Artists[ArtistRole.Composer] = new List<Artist>();
                track.Artists[ArtistRole.Composer].Add(artist);

                tracks.Add(track);
            }

            return tracks;
        }

        protected override List<Model.Track> DecodeTracks(QueryType type, Entity entity, string source)
        {
            switch(entity.Type)
            {
                case EntityType.Genre:
                    return DecodeTracksFromGenre(source);
                case EntityType.Artist:
                    return DecodeTracksFromArtist(source);
                default:
                    throw new NotSupportedException();
            }
        }

        protected override List<Artist> DecodeArtists(string source)
        {
            var document = new HtmlDocument();
            document.LoadHtml(source);
            var page = document.DocumentNode;

            var artists = new List<Artist>();

            var json_artists = (JArray)JObject.Parse(source)["results"];
            foreach(var artistNode in json_artists)
            {
                var name = (string)artistNode["artistName"];
                var id = (string)artistNode["artistId"];
                var artist = new Artist(id, name, m_repository);
                artists.Add(artist);
            }

            return artists;
        }

        protected override List<Genre> DecodeGenres(string source)
        {
            var document = new HtmlDocument();
            document.LoadHtml(source);
            var page = document.DocumentNode;

            var genres = new List<Genre>();

            var allGenre = new Genre("all", "All genres", m_repository);
            genres.Add(allGenre);

            var groupNodes = page.QuerySelector(".grid3-column");
            foreach(var column in groupNodes.ChildNodes.Where(c => c.Name == "ul"))
            {
                foreach(var groupNode in column.ChildNodes.Where(c => c.Name == "li"))
                {
                    var linkNode = groupNode.QuerySelector("a");
                    var id = linkNode.Attributes["href"].Value.Split('/').Last().Remove(0, 2);
                    var genre = new Genre(id, WebUtility.HtmlDecode(linkNode.InnerText), m_repository);
                    genres.Add(genre);
                }
            }

            return genres;
        }
    }
}
